﻿using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace Yoozoo.Art.Editor
{
    public class SkinningMeshCombine
    {
        [MenuItem("Tools/合并蒙皮网格")]
        public static void Do()
        {
            var prefabs = Selection.gameObjects;
            Execute(prefabs);
        }

        public static void Execute(GameObject[] prefabs)
        {
            if (prefabs == null || prefabs.Length == 0)
            {
                Debug.LogError("请选择两个以上Prefab, 后面的Prefab会合并到第一个");
                return;
            }

            bool isOk = true;
            foreach (var prefab in prefabs)
            {
                var prefabAssetType = PrefabUtility.GetPrefabAssetType(prefab);
                var prefabInstanceStatus = PrefabUtility.GetPrefabInstanceStatus(prefab);
                Debug.LogFormat("prefabAssetType: {0}, prefabInstanceStatus = {1}", prefabAssetType,
                    prefabInstanceStatus);
                if (prefabAssetType == PrefabAssetType.Regular &&
                    prefabInstanceStatus == PrefabInstanceStatus.Connected)
                {
                    // 正常预制体
                }
                else
                {
                    Debug.LogError("需要把预制体拖动到场景中，不要直接在工程内选中", prefab);
                    isOk = false;
                }
            }

            if (!isOk)
                return;

            var mainPrefab = prefabs[0];
            var mainBoneRoot = mainPrefab.transform.Find("Root");

            for (var i = 1; i < prefabs.Length; i++)
            {
                var prefab = prefabs[i];
                MergeNodes(prefab.transform.Find("Root"), mainBoneRoot);
                var skinnedMeshRenders = prefab.GetComponentsInChildren<SkinnedMeshRenderer>();
                foreach (var skinnedMeshRenderer in skinnedMeshRenders)
                {
                    string rootBonePath = GetNodePath(skinnedMeshRenderer.rootBone);
                    var bonePaths = new List<string>();
                    foreach (var bone in skinnedMeshRenderer.bones)
                    {
                        bonePaths.Add(GetNodePath(bone));
                    }

                    var newMeshObject = Object.Instantiate(skinnedMeshRenderer.gameObject, mainPrefab.transform);
                    newMeshObject.name = skinnedMeshRenderer.gameObject.name;
                    var newSkinnedMeshRenderer = newMeshObject.GetComponent<SkinnedMeshRenderer>();
                    newSkinnedMeshRenderer.rootBone = FindNode(mainBoneRoot, rootBonePath);
                    var bones = new Transform[bonePaths.Count];
                    for (var index = 0; index < bonePaths.Count; index++)
                    {
                        var bonePath = bonePaths[index];
                        bones[index] = FindNode(mainBoneRoot, bonePath);
                    }

                    newSkinnedMeshRenderer.bones = bones;
                }
            }
        }

        /// <summary>
        /// 将formRoot的子节点合并到toRoot中
        /// </summary>
        /// <param name="toRoot"></param>
        /// <param name="fromRoot"></param>
        private static void MergeNodes(Transform fromRoot, Transform toRoot)
        {
            int fromChildCount = fromRoot.childCount;
            for (int i = 0; i < fromChildCount; i++)
            {
                var fromChild = fromRoot.GetChild(i);

                var toChild = toRoot.Find(fromChild.name);
                if (toChild == null)
                {
                    var go = new GameObject(fromChild.name);
                    toChild = go.transform;
                    toChild.parent = toRoot;
                    toChild.localPosition = fromChild.localPosition;
                    toChild.localEulerAngles = fromChild.localEulerAngles;
                    toChild.localScale = fromChild.localScale;
                }
                else
                {
                    if (toChild.localPosition != fromChild.localPosition ||
                        toChild.localEulerAngles != fromChild.localEulerAngles ||
                        toChild.localScale != fromChild.localScale)
                    {
                        Debug.LogError("骨骼位置不统一：" + GetNodePath(fromChild), fromChild);
                    }
                }

                MergeNodes(fromChild, toChild);
            }
        }

        private static Transform FindNode(Transform root, string path)
        {
            var node = root.Find(path);
            if (node == null)
            {
                Debug.LogError("骨骼没有找到：" + path);
            }

            return node;
        }

        private static string GetNodePath(Transform node)
        {
            string path = node.name;
            var parent = node.parent;
            while (parent.name != "Root")
            {
                path = parent.name + "/" + path;
                parent = parent.parent;
            }

            //path = "Root/" + path;
            return path;
        }
    }
}
